package com.ruoyi.controller;


import com.ruoyi.service.*;
import com.ruoyi.utils.ByteUtils;
import com.ruoyi.utils.MyHttpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * This api is for watch uploading health data, the route /pb/upload can't be changed
 * content-type : application/octet-stream
 */
@RestController
@EnableAutoConfiguration
@RequestMapping("/pb")
public class DeviceController {
    private static final Logger log = LoggerFactory.getLogger(DeviceController.class);
    private MyHttpUtils http_utils = new MyHttpUtils();
    private ByteUtils bytes_utils = new ByteUtils();

    @Autowired
    private SleepPreprocessor sleepProcessor;

    @Autowired
    private OldManDataParser oldManDataParser;

    @Autowired
    private HistoryDataParser historyDataParser;

    @Autowired
    private RriPreprocessor rriProcessor;

    @Autowired
    private EcgPreprocessor ecgProcessor;
    @RequestMapping(value = "upload", method = RequestMethod.POST)
    private void uploadPBData(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        http_utils.printHeaders(req);

        int content_length = req.getContentLength();
        ServletInputStream instream = req.getInputStream();
        byte[] buffer = new byte[content_length];
        int offset = 0;
        while (true){
            int read_size = instream.read(buffer, offset, content_length);
            if(read_size<=0){
                break;
            }
            offset+=read_size;
        }
        instream.close();
        bytes_utils.bytesToHexString(buffer);
        offset = 0;
        //the first 15 bytes is deviceid/imei
        byte[] deviceId_bytes = new byte[15];
        System.arraycopy(buffer,offset,deviceId_bytes,0,15);
        String deviceId = new String(deviceId_bytes);
        log.info("deviceid: "+deviceId);
        offset += 15;
        //there maybe multiple data packages possible, need loop to parse all
        while (true){
            if(offset>content_length-9){
                break;
            }
            //parse header part which contains 8 bytes
            byte[] prefix_bytes = new byte[2];//fixed to 0x4454
            byte[] length_bytes = new byte[2];//length of the payload
            byte[] crc_bytes = new byte[2];//crc check
            /*
            the opt number of the payload
            opt number:
            0x0A - device info/realtime step/gnss
            0x80 - history data, history health/ecg
            0x00 - device info
             */
            byte[] opt_bytes = new byte[2];
            System.arraycopy(buffer,offset,prefix_bytes,0,2);
            if(prefix_bytes[0] != 0x44 || prefix_bytes[1] != 0x54){
                break;
            }
            offset += 2;
            System.arraycopy(buffer,offset,length_bytes,0,2);
            int length = bytes_utils.byteToPositiveInt(length_bytes[1])*0x100 + bytes_utils.byteToPositiveInt(length_bytes[0]);
            offset += 2;
            System.arraycopy(buffer,offset,crc_bytes,0,2);
            offset += 2;
            System.arraycopy(buffer,offset,opt_bytes,0,2);
            int opt = (opt_bytes[0] | opt_bytes[1]<<8) & 0x00FF;
            offset += 2;
            if(length<=0){
                bytes_utils.bytesToHexString(length_bytes);
                break;
            }

            //parse data part
            byte[] payload = new byte[length];
            System.arraycopy(buffer,offset,payload,0,length);
            offset += length;
            log.info(String.format("opt:%d",opt));
            IDataParser dataParser;
            if (opt == 0x0A) {
                oldManDataParser.DataParse(payload,deviceId);
            } else if (opt == 0x80) {
                historyDataParser.DataParse(payload,deviceId);
    /*
    this is for sleep calculation, show how to do some preprocess to prepare data
    and then invoke the calculation api
    */
                sleepProcessor.DataPrepare(payload);

    /*
    this is for ecg calculation, show how to do some preprocess to prepare data
    and then invoke the calculation api
    */
                ecgProcessor.DataPrepare(payload);

    /*
    this is for af calculation, show how to do some preprocess to prepare data
    and then invoke the calculation api
    */
                rriProcessor.DataPrepare(payload);
            }
        }
        //reponse content is text/plain, binary
        byte[] data = new byte[]{0x00};
        resp.getOutputStream().write(data);
        resp.getOutputStream().close();
    }

}
